package org.comanche.snaf.net.nio;

import java.net.SocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Collection;
import java.util.Iterator;

import org.comanche.snaf.core.polling.AbstractPollingAcceptor;
import org.comanche.snaf.core.service.Processor;

public class NioAcceptor extends AbstractPollingAcceptor<NioSession, ServerSocketChannel> {
	///////////////////////////////////////////////////////////
	// property member
	private Selector selector;
	
	///////////////////////////////////////////////////////////
	// constructor
	public NioAcceptor(Processor<NioSession> processor){
		super(processor);
	}
	
	//////////////////////////////////////////////////////////
	// inner class
	/**
	 * this is a adaptor class
	 */
	private static class ServerSocketIterator implements Iterator<ServerSocketChannel>{

		Iterator<SelectionKey> keys;
		
		public ServerSocketIterator(Collection<SelectionKey> keys){
			this.keys = keys.iterator();
		}
		
		public boolean hasNext() {
			return keys.hasNext();
		}

		public ServerSocketChannel next() {
			SelectionKey key = keys.next();
			
			if (key != null && key.isValid() && key.isAcceptable()){
				return (ServerSocketChannel)key.channel();
			}
		
			
			return null;
		}

		public void remove() {
			keys.remove();
		}
		
	}
	
	
	//////////////////////////////////////////////////////////
	// protected implements
	@Override
	protected void bindInternal(SocketAddress localAddress) throws Exception{
		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
		serverSocketChannel.configureBlocking(false);
		serverSocketChannel.socket().bind(localAddress, getBacklog());
		serverSocketChannel.socket().setReuseAddress(isReuseAddress());
		serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
	}

	@Override
	protected int select() throws Exception {
		return selector.select();
	}

	@Override
	protected void wakeup() {
		selector.wakeup();
	}


	@Override
	protected Iterator<ServerSocketChannel> getHandlers() {
		return new ServerSocketIterator(selector.selectedKeys());
	}

	@Override
	protected NioSession accept(Processor<NioSession> processor, ServerSocketChannel handler) throws Exception{
		// get select key
		SelectionKey key = handler.keyFor(selector);
		
		if (key.isValid() && key.isAcceptable()){
			SocketChannel client = handler.accept();
			
			return new NioSession(processor, client);
		}
		
		return null;
	}

}
